package org.fzkj.rpc.core.server;

import org.fzkj.rpc.core.protocol.RequestProtocol;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Method;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Map;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * rpc框架服务端
 * 1、暴露（注册）服务接口，就是让这个接口可以被远程调用
 * 2、启动服务
 */
public class RPCServer {

    // 定义一个集合用来存储所有的服务
    private Map<String, Object> serverMap = new ConcurrentHashMap<>();

    // 定义线程池
    ThreadPoolExecutor executor =
            new ThreadPoolExecutor(8, 20, 200, TimeUnit.MICROSECONDS, new ArrayBlockingQueue<>(20));

    /**
     * 暴露服务的方法
     * @param interfaceClass 服务接口
     * @param instance 具体的实现类
     */
    public void publishServerApi(Class<?> interfaceClass, Object instance){
        this.serverMap.put(interfaceClass.getName(), instance);
    }

    /**
     * 启动服务
     * @param port 指定启动的端口
     */
    public void startServer(int port) {
        try {
        // 创建网络服务端
            ServerSocket socket = new ServerSocket();
            socket.bind(new InetSocketAddress(port));
            System.out.println("============= RPC SERVER START SUCCESSFUL!!! =============");

            // 等待请求
            while (true) {
                executor.execute(new ServerTask(socket.accept()));
            }

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 处理客户端请求的线程类
     */
    private class ServerTask implements Runnable {

        private final Socket socket;

        public ServerTask (Socket socket){
            this.socket = socket;
        }

        @Override
        public void run() {
            // 处理具体的客户端请求
            try (
                    ObjectInputStream deSerializer = new ObjectInputStream(socket.getInputStream());
                    ObjectOutputStream serializer = new ObjectOutputStream(socket.getOutputStream());
                    ) {
                // 反序列化请求对象
                RequestProtocol reqProtocol = (RequestProtocol) deSerializer.readObject();
                // 获取请求对象中的信息
                // 1、获取接口全名称
                String interfaceClassName = reqProtocol.getInterfaceClassName();
                // 2、通过全名称去serverMap中找实例
                Object instance = serverMap.get(interfaceClassName);
                if (null == instance) return;
                // 3、获取客户端请求的方法 (反射)
                Method method = instance.getClass().getDeclaredMethod(reqProtocol.getMethodName(),
                        reqProtocol.getParameterType());
                // 4、执行方法
                Object result = method.invoke(instance, reqProtocol.getParameterValues());

                // 5、将结果写回
                serializer.writeObject(result);

            }catch (Exception e){
                e.printStackTrace();
            }
        }
    }


}
